
// <copyright file="DataReaderEnumerable.cs" company="Subhadra Software Solutions">
//   
// </copyright>
// <summary>
//   The create entity from reader delegate.
// </summary>

namespace SubhadraSolutions.Sharp.Utils.Data
{
    using System;
    using System.Collections;
    using System.Collections.Generic;
    using System.Data;
    using System.Diagnostics;

    #region Delegates

    /// <summary>
    /// The create entity from reader delegate.
    /// </summary>
    /// <param name="record">
    /// The record.
    /// </param>
    /// <typeparam name="T">
    /// </typeparam>
    public delegate T CreateEntityFromReaderDelegate<out T>(IDataRecord record);

    #endregion Delegates

    /// <summary>
    /// The data reader enumerable.
    /// </summary>
    /// <typeparam name="T">
    /// </typeparam>
    public class DataReaderEnumerable<T> : IEnumerable<T>
        where T : class
    {
        #region Fields

        /// <summary>
        /// The close connection after reading.
        /// </summary>
        private readonly bool closeConnectionAfterReading;

        /// <summary>
        /// The connection.
        /// </summary>
        private readonly IDbConnection connection;

        /// <summary>
        /// The create entity from reader delegate.
        /// </summary>
        private readonly CreateEntityFromReaderDelegate<T> createEntityFromReaderDelegate;

        /// <summary>
        /// The reader.
        /// </summary>
        private readonly IDataReader reader;

        #endregion Fields

        #region Constructors and Finalizers

        /// <summary>
        /// Initializes a new instance of the <see cref="DataReaderEnumerable{T}"/> class.
        /// </summary>
        /// <param name="reader">
        /// The reader.
        /// </param>
        /// <param name="createEntityFromReaderDelegate">
        /// The create entity from reader delegate.
        /// </param>
        /// <param name="connection">
        /// The connection.
        /// </param>
        /// <param name="closeConnectionAfterReading">
        /// The close connection after reading.
        /// </param>
        public DataReaderEnumerable(IDataReader reader, CreateEntityFromReaderDelegate<T> createEntityFromReaderDelegate, IDbConnection connection, bool closeConnectionAfterReading)
        {
            this.reader = reader;
            this.connection = connection;
            this.createEntityFromReaderDelegate = createEntityFromReaderDelegate;
            this.closeConnectionAfterReading = closeConnectionAfterReading;
        }

        #endregion Constructors and Finalizers

        #region Public Methods and Operators

        /// <summary>
        /// The get enumerator.
        /// </summary>
        /// <returns>
        /// The <see cref="IEnumerator"/>.
        /// </returns>
        public IEnumerator<T> GetEnumerator()
        {
            return new DataReaderEnumerator(this.reader, this.createEntityFromReaderDelegate, this.connection, this.closeConnectionAfterReading);
        }

        #endregion Public Methods and Operators

        #region Explicit Interface Methods

        /// <summary>
        /// The get enumerator.
        /// </summary>
        /// <returns>
        /// The <see cref="IEnumerator"/>.
        /// </returns>
        IEnumerator IEnumerable.GetEnumerator()
        {
            return new DataReaderEnumerator(this.reader, this.createEntityFromReaderDelegate, this.connection, this.closeConnectionAfterReading);
        }

        #endregion Explicit Interface Methods

        /// <summary>
        /// The data reader enumerator.
        /// </summary>
        private sealed class DataReaderEnumerator : IEnumerator<T>
        {
            #region Fields

            /// <summary>
            /// The close connection after reading.
            /// </summary>
            private readonly bool _closeConnectionAfterReading;

            /// <summary>
            /// The connection.
            /// </summary>
            private readonly IDbConnection _connection;

            /// <summary>
            /// The create entity from reader delegate.
            /// </summary>
            private readonly CreateEntityFromReaderDelegate<T> _createEntityFromReaderDelegate;

            /// <summary>
            /// The reader.
            /// </summary>
            private readonly IDataReader _reader;

            #endregion Fields

            #region Constructors and Finalizers

            /// <summary>
            /// Initializes a new instance of the <see cref="DataReaderEnumerator"/> class.
            /// </summary>
            /// <param name="reader">
            /// The reader.
            /// </param>
            /// <param name="createEntityFromReaderDelegate">
            /// The create entity from reader delegate.
            /// </param>
            /// <param name="connection">
            /// The connection.
            /// </param>
            /// <param name="closeConnectionAfterReading">
            /// The close connection after reading.
            /// </param>
            public DataReaderEnumerator(IDataReader reader, CreateEntityFromReaderDelegate<T> createEntityFromReaderDelegate, IDbConnection connection, bool closeConnectionAfterReading)
            {
                this._reader = reader;
                this._connection = connection;
                this._createEntityFromReaderDelegate = createEntityFromReaderDelegate;
                this._closeConnectionAfterReading = closeConnectionAfterReading;
            }

            #endregion Constructors and Finalizers

            #region Explicit Interface Properties

            /// <summary>
            /// Gets the current.
            /// </summary>
            object IEnumerator.Current
            {
                get
                {
                    return this._createEntityFromReaderDelegate(this._reader);
                }
            }

            /// <summary>
            /// Gets the current.
            /// </summary>
            T IEnumerator<T>.Current
            {
                get
                {
                    return this._createEntityFromReaderDelegate(this._reader);
                }
            }

            #endregion Explicit Interface Properties

            #region Public Methods and Operators

            /// <summary>
            /// The dispose.
            /// </summary>
            public void Dispose()
            {
                if (this._closeConnectionAfterReading)
                {
                    try
                    {
                        this._connection.Close();
                    }
                    catch (Exception ex)
                    {
                        Debug.WriteLine(ex);
                    }
                }
            }

            /// <summary>
            /// The move next.
            /// </summary>
            /// <returns>
            /// The <see cref="bool"/>.
            /// </returns>
            public bool MoveNext()
            {
                if (this._reader.Read())
                {
                    return true;
                }

                if (this._closeConnectionAfterReading)
                {
                    this._connection.Close();
                }

                return false;
            }

            /// <summary>
            /// The reset.
            /// </summary>
            public void Reset()
            {
            }

            #endregion Public Methods and Operators
        }
    }
}